import { VITE_DEV_SERVER_PROXY_PREFIX } from '@/config/EnvironmentVariable.ts'
import type { HttpInterceptorManagerSpec } from '@/config/httpClient/HttpInterceptor.ts'
import { HttpInterceptorDelegationManager } from '@/config/httpClient/HttpInterceptorDelegationManager.ts'
import { HttpInterceptorManager } from '@/config/httpClient/HttpInterceptorManager.ts'
import axios, { type AxiosInstance, type AxiosRequestConfig, type AxiosResponse } from 'axios'

/**
 * HTTP 客户端
 */
export class HttpClient {

    /**
     * 拦截器管理器
     */
    public readonly interceptorManager: HttpInterceptorManagerSpec

    /**
     * axios 实例
     */
    private readonly fetchImpl: AxiosInstance

    /**
     * axios 实例
     */
    private readonly xhrImpl: AxiosInstance

    public constructor() {
        this.fetchImpl = axios.create({
            baseURL: VITE_DEV_SERVER_PROXY_PREFIX || '',
            timeout: 30 * 1000,
            adapter: 'fetch',
        })

        this.xhrImpl = axios.create({
            baseURL: VITE_DEV_SERVER_PROXY_PREFIX || '',
            timeout: 30 * 1000,
            adapter: 'xhr',
        })

        this.interceptorManager = new HttpInterceptorDelegationManager([
            new HttpInterceptorManager(this.fetchImpl),
            new HttpInterceptorManager(this.xhrImpl),
        ])
    }

    // noinspection JSUnusedGlobalSymbols
    /**
     * 发送 HTTP 请求 使用默认客户端
     * @param config 请求配置
     * @return 包含 AxiosResponse 结构的响应数据
     */
    public request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R> {
        return this.fetchImpl.request<T, R, D>(config)
    }

    /**
     * 发送 HTTP 请求 使用默认客户端, 解开第一层 data
     * @param config 请求配置
     * @return 响应数据
     */
    public async send<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T> {
        return (await this.fetchImpl.request<T, AxiosResponse<T>, D>(config)).data
    }

    /**
     * 文件上传 使用 XHR 客户端
     */
    public async upload<T = any, D = any>(config: AxiosRequestConfig<D>): Promise<T> {
        return (await this.xhrImpl.request<T, AxiosResponse<T>, D>(config)).data
    }

}
